package com.siss.tenancy.user.aop;

import com.siss.tenancy.util.IPCommonUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 通过AOP自定义切面，实现CRUD操作前 公有字段{创建者，创建时间，修改者，修改时间，删除者，删除时间，是否删除 }的统一设置。
 * 
 * @author yingw
 * @version 1.0
 */
@Aspect
@Configuration
public class AutoMapperAspect {

	private static final Logger logger = LoggerFactory.getLogger(AutoMapperAspect.class);
	
	// 切点
	@Pointcut("@annotation(com.siss.tenancy.user.aop.AutoMapper)")
	public void mapper(){
		
	}
	
	@Around("mapper()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
		
		Signature signature = point.getSignature();
		
		// 目标方法参数数组
		Object[] args = point.getArgs();
		
		MethodSignature methodSignature = (MethodSignature) signature;
		
		// 获取目标方法Method对象
		Method method = methodSignature.getMethod();
	
		// 获取目标方法上的@AutoMapper注解
		AutoMapper annotation = method.getAnnotation(AutoMapper.class);
		// 注解设置的参数名称
		String annotation_value = annotation.value();
		// 注解设置的操作方法
		AutoMapperEnum annotation_method = annotation.method();
		
		// 目标方法参数名称数组
		String[] parameterNames = methodSignature.getParameterNames();
		for(int index = 0; index < parameterNames.length; index++){
			if(parameterNames[index].equals(annotation_value)){
				// 得到注解value指定的参数名称相应的对象
				Object object = args[index];
				
				// 获取HttpServletRequest对象
				ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
				HttpServletRequest request = null;
				if(requestAttributes != null)
		    	 request = requestAttributes.getRequest();		    	
				setBaseValueOnObject(object, annotation_method, request);
			}
		}
		
		 // 目标方法执行
		 return point.proceed();

	}
	
	/**
	 * 设置公有字段
	 * 
	 * @param object			注解指定的参数对象
	 * @param annotation_method 操作方式
	 * @param updatePlatId 		是否设置platId值
	 * @param request
	 * @throws Exception 
	 */
	public void setBaseValueOnObject(Object object, AutoMapperEnum annotation_method, HttpServletRequest request) throws Exception{
		
		String userId = "1";//AuthenticationUtils.getAuthUserId();	// 用户id
		if(userId ==null || userId == ""){
        	userId = "1";
        }
		String ip = "";
		if (request != null)
			ip = IPCommonUtil.getIpAddr(request);
		
		// null
		Object nonvalue = null;
		// 当前系统时间
		Date currentTime = new Date();
		Class<?> clazz = object.getClass();	
		
		try {
			
			int state = 0;	// 标识是否存在公有方法
			
			Method setInsertUserMethod = null;	// 设置创建用户
			Method setInsertTimeMethod = null;	// 设置创建时间
			Method setUpdateUserMethod = null;	// 设置修改用户
			Method setUpdateTimeMethod = null;	// 设置修改时间
			Method setDeleteSaIdMethod = null;	// 设置删除用户
			Method setDeleteTimeMethod = null;	// 设置删除时间
			Method setDeletedMethod = null;	// 设置是否删除
			Method setIpMethod = null;	// 设置是否删除
			
			Method[] methods = clazz.getMethods();
			for(Method m : methods){

			   if("setInsertSaId".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == String.class){
						setInsertUserMethod = clazz.getMethod("setInsertSaId", String.class);	
						state++;
					}
				}else if("setInsertTime".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == Date.class){
						setInsertTimeMethod = clazz.getMethod("setInsertTime", Date.class);		
						state++;
					}
				}else if("setUpdateSaId".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == String.class){
						setUpdateUserMethod = clazz.getMethod("setUpdateSaId", String.class);	
						state++;
					}
				}else if("setUpdateTime".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == Date.class){
						setUpdateTimeMethod = clazz.getMethod("setUpdateTime", Date.class);		
						state++;
					}
				}else if("setDeleteSaId".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == String.class){
						setDeleteSaIdMethod = clazz.getMethod("setDeleteSaId", String.class);	
						state++;
					}
				}else if("setDeleteTime".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == Date.class){
						setDeleteTimeMethod = clazz.getMethod("setDeleteTime", Date.class);		
						state++;
					}
				}else if("setDeleted".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == Boolean.class){
						setDeletedMethod = clazz.getMethod("setDeleted", Boolean.class);		
						state++;
					}
				}else if("setIp".equals(m.getName())){
					Class<?>[] parameterTypes = m.getParameterTypes();
					if(parameterTypes.length == 1 && parameterTypes[0] == String.class){
						setIpMethod = clazz.getMethod("setIp", String.class);		
						state++;
					}
				}
				
			}
			
			if(state > 0){
			
				switch (annotation_method) {
				case INSERT:
					if(setInsertUserMethod != null){
						setInsertUserMethod.invoke(object, userId);
					}
					
					if(setInsertTimeMethod != null){
						setInsertTimeMethod.invoke(object, currentTime);
					}
					
					if(setUpdateUserMethod != null){
						setUpdateUserMethod.invoke(object, userId);
					}
					
					if(setUpdateTimeMethod != null){
						setUpdateTimeMethod.invoke(object, currentTime);
					}
					
					if(setDeleteSaIdMethod != null){
						setDeleteSaIdMethod.invoke(object, nonvalue);
					}
					
					if(setDeleteTimeMethod != null){
						setDeleteTimeMethod.invoke(object, nonvalue);
					}
					
					if(setDeletedMethod != null){
						setDeletedMethod.invoke(object, false);
					}
					if(setIpMethod != null){
						setIpMethod.invoke(object, ip);
					}
					
					break;
				case UPDATE:

					
					if(setInsertUserMethod != null){
						setInsertUserMethod.invoke(object, nonvalue);
					}
					
					if(setInsertTimeMethod != null){
						setInsertTimeMethod.invoke(object, nonvalue);
					}
					
					if(setUpdateUserMethod != null){
						setUpdateUserMethod.invoke(object, userId);
					}
					
					if(setUpdateTimeMethod != null){
						setUpdateTimeMethod.invoke(object, currentTime);
					}
					
					if(setDeleteSaIdMethod != null){
						setDeleteSaIdMethod.invoke(object, nonvalue);
					}
					
					if(setDeleteTimeMethod != null){
						setDeleteTimeMethod.invoke(object, nonvalue);
					}
					
					if(setDeletedMethod != null){
						setDeletedMethod.invoke(object, nonvalue);
					}
					if(setIpMethod != null){
						setIpMethod.invoke(object, ip);
					}
					break;
				case DELETE:
					
					if(setInsertUserMethod != null){
						setInsertUserMethod.invoke(object, nonvalue);
					}
					
					if(setInsertTimeMethod != null){
						setInsertTimeMethod.invoke(object, nonvalue);
					}
					
					if(setUpdateUserMethod != null){
						setUpdateUserMethod.invoke(object, nonvalue);
					}
					
					if(setUpdateTimeMethod != null){
						setUpdateTimeMethod.invoke(object, nonvalue);
					}
					
					if(setDeleteSaIdMethod != null){
						setDeleteSaIdMethod.invoke(object, userId);
					}
					
					if(setDeleteTimeMethod != null){
						setDeleteTimeMethod.invoke(object, currentTime);
					}
					
					if(setDeletedMethod != null){
						setDeletedMethod.invoke(object, true);
					}
					if(setIpMethod != null){
						setIpMethod.invoke(object, ip);
					}
					
					break;
				case SELECT:
					
					if(setDeletedMethod != null){
						setDeletedMethod.invoke(object, false);
					}
					
					break;
				
				default:
					break;
				}
				
			}
			
		} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			e.printStackTrace();
			logger.info("NoSuchMethodException");
		}	
		

		
	}
	
}
